package org.lboot.flow.processor.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONUtil;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.lboot.flow.constant.*;
import org.lboot.flow.loader.TaskUserLoader;
import org.lboot.flow.model.FlowModel;
import org.lboot.flow.model.node.BaseModel;
import org.lboot.flow.model.node.TaskModel;
import org.lboot.flow.module.assign.FlowTaskAssign;
import org.lboot.flow.module.assign.FlowTaskAssignService;
import org.lboot.flow.module.audit.FlowAudit;
import org.lboot.flow.module.audit.FlowAuditService;
import org.lboot.flow.module.event.FlowCustomEvent;
import org.lboot.flow.module.work.FlowWork;
import org.lboot.flow.module.work.FlowWorkService;
import org.lboot.flow.module.work.params.FlowTaskParams;
import org.lboot.flow.parser.FlowNodeParser;
import org.lboot.flow.processor.FlowNodeProcessor;
import org.lboot.flow.event.system.FlowProcessEvent;
import org.lboot.flow.event.user.FlowCloseEvent;
import org.springframework.context.ApplicationContext;
import org.springframework.data.domain.Example;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author kindear
 * 任务节点
 */
@Slf4j
@Service
@AllArgsConstructor
public class TaskNodeProcessorImpl implements FlowNodeProcessor {
    FlowNodeParser flowNodeParser;

    FlowWorkService flowWorkService;

    FlowAuditService flowAuditService;

    FlowTaskAssignService flowTaskAssignService;

    TaskUserLoader taskUserLoader;

    @Resource
    ApplicationContext context;

    @Override
    public String getNodeType() {
        return FlowNodeTypeConst.TASK_NODE;
    }

    @SneakyThrows
    @Override
    public void process(FlowWork flowWork, FlowTaskParams taskParams) {
        FlowWork oldFlow = new FlowWork();
        BeanUtil.copyProperties(flowWork,oldFlow, CopyOptions.create().setIgnoreError(true).setIgnoreNullValue(true));
        // 流程执行到下一步
        BaseModel currentNode = flowWork.getCurrentModel();
        // 获取节点类型
        TaskModel taskModel = (TaskModel) currentNode;
        // 获取执行类型
        String performType = taskModel.getPerformType();
        // 查询审批信息
        FlowAudit audit = new FlowAudit();
        audit.setFlowNodeId(taskModel.getId());
        audit.setFlowNodeName(taskModel.getName());
        audit.setFlowWorkId(flowWork.getId());
        Example<FlowAudit> example = Example.of(audit);
        List<FlowAudit> audits = flowAuditService.getExample(example);
        // 如果没有审计记录 ->
        if (audits.isEmpty()){
            return;
        }
        // 如果是竞签
        if (performType.equals(TaskPerformTypeConst.ANY) || performType.equals(TaskPerformTypeConst.RACE)){
            if (audits.size() > 1){
                log.warn("流程实例{}竞签存在异常",flowWork.getId());
            }
            FlowAudit flowAudit = audits.get(0);
            // 如果是通过 ->
            if (flowAudit.getAuditResult().equals(FlowTaskAuditConst.PASS)){
                // 开始后置事件
                BaseModel nextModel = flowWork.getNextModel();
                flowWork.setCurrentNodeId(nextModel.getId());
                flowWork.setCurrentNodeType(nextModel.getNodeType());
                flowWork.setNextNodeId(nextModel.getNextNodeId());
                flowWorkService.updateOne(flowWork);
                // 发布流程流转事件
                context.publishEvent(new FlowProcessEvent(this,oldFlow,flowWork));
            }else {
                // 如果是拒绝 直接关闭
                flowWork.setFlowWorkStatus(FlowWorkStatusEnum.CLOSED.value);
                flowWork.setStatus(0);
                flowWorkService.updateOne(flowWork);
                // 发布流程关闭事件
                context.publishEvent(new FlowCloseEvent(this,flowWork));
            }
        }else if (performType.equals(TaskPerformTypeConst.ALL)){
            // 判断符合条件的用户
            FlowTaskAssign assign = new FlowTaskAssign();
            assign.setFlowCode(flowWork.getFlowCode());
            assign.setFlowNodeId(flowWork.getCurrentNodeId());
            Example<FlowTaskAssign> assignExample = Example.of(assign);
            List<FlowTaskAssign> assigns = flowTaskAssignService.getExample(assignExample);
            List<String> userIds = taskUserLoader.load(assigns);
            int passNum = 0;
            int rejectNum = 0;
            for (FlowAudit ele:audits){
                if (ele.getAuditResult().equals(FlowTaskAuditConst.PASS)){
                    passNum++;
                }else {
                    rejectNum++;
                }
            }
            // 审计记录 全部通过
            if (passNum == userIds.size()){
                BaseModel nextModel = flowWork.getNextModel();
                flowWork.setCurrentNodeId(nextModel.getId());
                flowWork.setCurrentNodeType(nextModel.getNodeType());
                flowWork.setNextNodeId(nextModel.getNextNodeId());
                flowWorkService.updateOne(flowWork);
                // 发布流程流转事件
                context.publishEvent(new FlowProcessEvent(this,oldFlow,flowWork,taskParams));
            }else if (rejectNum > 0){
                // 如果是拒绝
                flowWork.setFlowWorkStatus(FlowWorkStatusEnum.CLOSED.value);
                flowWork.setStatus(0);
                flowWorkService.updateOne(flowWork);
                // 发布流程关闭事件
                context.publishEvent(new FlowCloseEvent(this,flowWork));
            }
        }else if (performType.equals(TaskPerformTypeConst.CUSTOM)){
            // 自定义规则
            String customPassRule = taskModel.getCustomPassRule();
            String customRejectRule = taskModel.getCustomRejectRule();
            // 获取
            FlowTaskAssign assign = new FlowTaskAssign();
            assign.setFlowCode(flowWork.getFlowCode());
            assign.setFlowNodeId(flowWork.getCurrentNodeId());
            Example<FlowTaskAssign> assignExample = Example.of(assign);
            List<FlowTaskAssign> assigns = flowTaskAssignService.getExample(assignExample);
            // 获取全部具有审核权限的用户
            List<String> userIds = taskUserLoader.load(assigns);
            Map<String, Integer> taskMap = new HashMap<>();
            taskMap.put("all", userIds.size());
            // 获取审核通过人数
            int passNum = 0;
            int rejectNum = 0;
            for (FlowAudit ele:audits){
                if (ele.getAuditResult().equals(FlowTaskAuditConst.PASS)){
                    passNum++;
                }else {
                    rejectNum++;
                }
            }
            taskMap.put("pass", passNum);
            taskMap.put("reject", rejectNum);
            String json = JSONUtil.toJsonStr(taskMap);
            ScriptEngineManager manager = new ScriptEngineManager();
            // 获取 JavaScript 的 ScriptEngine
            ScriptEngine engine = manager.getEngineByName("JavaScript");
            // 将 JSON 字符串传递给脚本引擎
            try {
                // 解析 JSON 字符串为 JavaScript 对象
                engine.eval("var $ = " + json + ";");
                // 执行脚本获取值
                Boolean execPassResult = (Boolean) engine.eval(customPassRule);
                Boolean execRejectResult = (Boolean) engine.eval(customRejectRule);
                //如果是通过
                if (execPassResult){
                    // 发布流程流转事件
                    context.publishEvent(new FlowProcessEvent(this,oldFlow,flowWork,taskParams));
                }else if (execRejectResult){
                    // 发布流程关闭事件
                    context.publishEvent(new FlowCloseEvent(this,flowWork));
                }
            } catch (ScriptException e) {
                e.printStackTrace();
            }

        }
    }

    @Override
    public void back(FlowWork flowWork, FlowTaskParams params) {

    }
}
